package triannon.client.sprites;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;

import org.jdom.Element;

import triannon.client.sprites.renderer.IRenderer;
import triannon.client.util.TMath;

public abstract class AbstractSprite implements ISprite {

	private final SpriteType type;
	protected long frame = 0;
	protected int width, height;
	protected int x = 0, y = 0;
	protected final String key;
	protected Fraction fraction;
	protected final SpriteInfo spriteInfo;
	protected Animation animation;

	protected IRenderer renderer;
	protected boolean alreadyPainted = false;
	protected final boolean high;

	protected Field field;

	private int time = 0;

	private Rectangle rect;

	public AbstractSprite(SpriteType type, String key, Fraction fraction) {
		this.type = type;
		this.key = key;
		this.fraction = fraction;
		this.spriteInfo = SpriteInfoMap.getInstance().get(key);
		this.animation = spriteInfo.getAnimations().getDefault();
		this.width = spriteInfo.getWidth();
		this.height = spriteInfo.getHeight();
		this.renderer = animation.getStartFrame();
		this.high = animation.getImageHeight() > height;
		updateRect();
	}

	public boolean isHigh() {
		return high;
	}

	protected void setAnimation(AnimationKey animationKey) {
		Animation ani = spriteInfo.getAnimations().get(animationKey);
		if (ani != null) {
			this.animation = ani;
			this.renderer = animation.getStartFrame();
		}
	}

	@Override
	public SpriteType getSpriteType() {
		return type;
	}

	public Animation getAnimation() {
		return animation;
	}

	@Override
	public boolean isBlocker() {
		switch (type) {
		case BUILDING:
		case UNIT:
		case ENVIRONMENT:
			return true;
		case AIRUNIT:
		case BACKGROUND:
		case BUILDING_HIGH:
			return false;
		}

		return false;
	}

	@Override
	public void update(long tpf) {
		frame++;

		if (animation.getAnimationSpeed() > 0) {
			int updateEveryMS = (int) (33f / animation.getAnimationSpeed());

			time += tpf;
			if (updateEveryMS > 0 && time > updateEveryMS) {
				this.renderer = animation.incFrame(time / updateEveryMS);
				time %= updateEveryMS;
			}
		}
	}

	void setField(Field field) {
		this.field = field;
	}

	public void setX(int x) {
		this.x = x;
		updateRect();
	}

	public void setY(int y) {
		this.y = y;
		updateRect();
	}

	public void setLocation(int x, int y) {
		this.x = x;
		this.y = y;
		updateRect();
	}

	protected void updateRect() {
		this.rect = new Rectangle(x, y, width, height);
	}

	public Rectangle getRect() {
		return rect;
	}

	@Override
	public String getKey() {
		return key;
	}

	@Override
	public Color getBKColor() {
		return fraction.getColor();
	}

	public void setFraction(Fraction fraction) {
		this.fraction = fraction;
	}

	@Override
	public int getHeight() {
		return height;
	}

	@Override
	public int getWidth() {
		return width;
	}

	@Override
	public int getX() {
		return x;
	}

	@Override
	public int getY() {
		return y;
	}

	@Override
	public void paint(Graphics2D g) {
		if (!alreadyPainted) {
			alreadyPainted = true;
			renderer.paint(g, x - spriteInfo.getOriginX(), y
					- spriteInfo.getOriginY());
		}
	}

	public void setAlreadyPainted(boolean alreadyPainted) {
		this.alreadyPainted = alreadyPainted;
	}

	@Override
	public Element toXML() {
		Element element = new Element("sprite");
		element.setAttribute("type", type.toString().toLowerCase());
		element.setAttribute("key", key);
		element.setAttribute("x", String.valueOf(getLevelX()));
		element.setAttribute("y", String.valueOf(getLevelY()));
		element.setAttribute("fraction", fraction.toString().toLowerCase());

		return element;
	}

	@Override
	public void parseXML(Element element) {

	}

	@Override
	public String toString() {
		return "Sprite(" + type + ") at (" + TMath.toLevelCoorninates(getCenterX())
				+ "," + TMath.toLevelCoorninates(getCenterY()) + ")";
	}

	public int getCenterX() {
		return x + width / 2;
	}

	public int getCenterY() {
		return y + height / 2;
	}

	@Override
	public int getLevelX() {
		return TMath.toLevelCoorninates(x);
	}

	@Override
	public int getLevelY() {
		return TMath.toLevelCoorninates(y);
	}

}
